package top.codef.secure.config.delegates;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import top.codef.secure.abstracts.RequestUrlDetailService;
import top.codef.secure.authority.AuthWithRequestUrl;
import top.codef.secure.authority.MightyAuth;
import top.codef.secure.config.interfaces.CerberusHttpSecurityConfig;
import top.codef.secure.properties.CerberusAuthorizedProperties;
import top.codef.secure.requesturl.RequestUrl;

@Configuration
@Order(8)
@EnableConfigurationProperties({ CerberusAuthorizedProperties.class })
public class CerberusAuthConfig implements CerberusHttpSecurityConfig {

	@Autowired(required = false)
	private RequestUrlDetailService requestUrlDetailService;

	@Autowired
	private CerberusAuthorizedProperties cerberusAuthorizedProperties;

	private final Log logger = LogFactory.getLog(getClass());

	@Override
	public void secure(HttpSecurity httpSecurity) throws Exception {
		logger.debug("开始配置权限");
		var ignoringList = cerberusAuthorizedProperties.getPermitAll();
		if (ignoringList != null) {
			httpSecurity.authorizeHttpRequests(customer -> {
				ignoringList.forEach(x -> {
					logger.debug("add ignoring Pattern:" + x);
					customer.requestMatchers(x).permitAll();
				});
			});
		}
		if (requestUrlDetailService == null)
			return;
		List<AuthWithRequestUrl> list = requestUrlDetailService.details().stream()
				.filter(x -> x.getRequestUrlList().size() > 0).collect(toList());
		if (list.size() == 0)
			return;
		Map<RequestUrl, List<MightyAuth>> interfaceMap = list.stream()
				.flatMap(x -> x.getRequestUrlList().stream().map(y -> new AuthRequestInterface(x.getAuth(), y)))
				.collect(groupingBy(AuthRequestInterface::getRequestUrl,
						mapping(AuthRequestInterface::getAuth, toList())));
		interfaceMap.forEach((url, auth) -> {
			url.getUrlPattern().getHttpMethods().forEach(method -> {
				try {
					httpSecurity.authorizeHttpRequests(x -> x
							.requestMatchers(HttpMethod.valueOf(method.toString()),
									url.getUrlPattern().getServiceUriPattern())
							.hasAnyRole(auth.stream().map(MightyAuth::getAuthName).toArray(String[]::new)));
				} catch (Exception e) {
					logger.warn("url bind auth error!", e);
				}
			});
		});
	}

	class AuthRequestInterface {

		private MightyAuth auth;

		private RequestUrl requestUrl;

		public AuthRequestInterface(MightyAuth auth, RequestUrl requestUrl) {
			super();
			this.auth = auth;
			this.requestUrl = requestUrl;
		}

		public MightyAuth getAuth() {
			return auth;
		}

		public void setAuth(MightyAuth auth) {
			this.auth = auth;
		}

		public RequestUrl getRequestUrl() {
			return requestUrl;
		}

		public void setRequestUrl(RequestUrl requestUrl) {
			this.requestUrl = requestUrl;
		}
	}
}
